local PSO = require "PSO"

local LDPSO = PSO:new( {
      num_stagnation = 1;
      max_num_stagnation =  5;
      num_of_dead_particles  = 10;
})


---------------------------------------------------------------------------------
--在找出全局最优粒子（比较每一个粒子的历史最优数据）
function LDPSO:get_global_best_value()
    table.sort(self.swarm, function(t1, t2) return t1.best_value < t2.best_value end)
    return self.swarm[1],self.swarm[1].best_value;
end
---------------------------------------------------------------------------------

function LDPSO:update_best_pos_and_val()
	
	self.last_global_best_value = self.global_best_value;

	----------------------------------------------------------------------------------------------------------------------------------------
	-- update individual and global best position and val
	for jj = 1 , self.swarm_size do			
		if self.swarm[jj].value < self.swarm[jj].best_value then              -- if new position is better
		    for k,v in pairs(self.par) do
			 self.swarm[jj][k].best_pos =  self.swarm[jj][k].pos ; -- update best position
		    end
		    self.swarm[jj].best_value = self.swarm[jj].value;              -- % and best value
		    self.swarm[jj].best_num_iter= self.num_iter;              -- % and the iterations
		end       
	end	    
	best_swarm, self.global_best_value= self:get_global_best_value();	
	self.best_swarm = best_swarm;	
	----------------------------------------------------------------------------------------------------------------------------------------
	
	if math.abs( self.global_best_value - self.last_global_best_value ) < 1e-10 then
		self.num_stagnation = self.num_stagnation + 1;
	else
		self.num_stagnation = 1;
	end

	----------------------------------------------------------------------------------------------------------------------------------------
	-- save best position and val
	if mpi.world.rank() == 0 then	
		self:writebest2file( );
	end
	----------------------------------------------------------------------------------------------------------------------------------------
end

function LDPSO:writebest2file( )--~ 	print( self.results_path );
	local file = io.open(self.best_results_path, "a")
	--file:write(self.num_iter,"\t", self.best_swarm.index,"\t")
	file:write(self.num_iter,"\t", self.best_swarm.index,"\t",self.best_swarm.best_num_iter)
	for k,v in pairs(self.par) do
             file:write("\t",self.best_swarm[k].best_pos)
        end
	file:write("\t",self.global_best_value, "\t",self.num_stagnation,"\n")
	file:close()	
end

---------------------------------------------------------------------------------
--自然选择，将当前适应度较差的一半粒子，位置值用适用度较好的一半粒子替代，但是保留该粒子的历史最优值
function LDPSO:natural_selection()
	table.sort(self.swarm, function(t1, t2) return t1.value < t2.value end)
	for jj = 1,math.min( self.swarm_size/2, self.num_of_dead_particles) do
		for k,v in pairs(self.par) do
			self.swarm[self.swarm_size - jj +1][k].pos = self.swarm[jj][k].pos
			self.swarm[self.swarm_size - jj +1][k].vel = self.swarm[jj][k].vel
			self.swarm[self.swarm_size - jj +1][k].value = self.swarm[jj][k].value
		end
	end
end
---------------------------------------------------------------------------------

---------------------------------------------------------------------------------
--精英学习变异
function LDPSO:learning_mutation()
end
---------------------------------------------------------------------------------


function LDPSO:step()	
	self.num_iter = self.num_iter+1;	 	
	print( "num_iter:",self.num_iter)
	 	
	----------------------------------------------------------------------------------------------------------------------------------------
	 --update  position 
	 self:update_position()
	----------------------------------------------------------------------------------------------------------------------------------------

	----------------------------------------------------------------------------------------------------------------------------------------
	--envaluation 
	 self:evaluate()
	----------------------------------------------------------------------------------------------------------------------------------------

	----------------------------------------------------------------------------------------------------------------------------------------
	--natural_selection 
	self:natural_selection ()
	----------------------------------------------------------------------------------------------------------------------------------------
	
	----------------------------------------------------------------------------------------------------------------------------------------
	--update  individual and global best position and val
	self:update_best_pos_and_val()
	----------------------------------------------------------------------------------------------------------------------------------------
	
	----------------------------------------------------------------------------------------------------------------------------------------
	--- updating velocity vectors
	self:update_velocity()
	----------------------------------------------------------------------------------------------------------------------------------------	
end

return LDPSO;